package edu.po.au.server.service;

import edu.po.au.server.PMF;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.datanucleus.query.JDOCursorHelper;

import java.util.HashMap;
import java.util.List;

import javax.annotation.Nullable;
import javax.inject.Named;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import edu.po.au.server.EPConstants;
import edu.po.au.server.domain.User;

@Api(name = "au", version=EPConstants.API_VERSION, 
		clientIds = {com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID, EPConstants.WEB_CLIENT_ID}, 
		audiences = {EPConstants.ANDROID_AUDIENCE}, 
		scopes={"https://www.googleapis.com/auth/userinfo.email"})
public class UserEndpoint {

	@SuppressWarnings({ "unchecked", "unused" })
  @ApiMethod(name = "user.list", path="user/list")
	public CollectionResponse<User> listUser(
			@Nullable @Named("cursor") String cursorString,
			@Nullable @Named("limit") Integer limit) {

		PersistenceManager mgr = null;
		Cursor cursor = null;
		List<User> execute = null;

		try {
			mgr = getPersistenceManager();
			Query query = mgr.newQuery(User.class);
			if (cursorString != null && cursorString != "") {
				cursor = Cursor.fromWebSafeString(cursorString);
				HashMap<String, Object> extensionMap = new HashMap<String, Object>();
				extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
				query.setExtensions(extensionMap);
			}

			if (limit != null) {
				query.setRange(0, limit);
			}

			execute = (List<User>) query.execute();
			cursor = JDOCursorHelper.getCursor(execute);
			if (cursor != null)
				cursorString = cursor.toWebSafeString();

			// Tight loop for fetching all entities from datastore and accomodate for lazy fetch.
			for (User obj : execute)
				;
			
		} finally {
			mgr.close();
		}

		return CollectionResponse.<User> builder().setItems(execute).setNextPageToken(cursorString).build();
	}

  @ApiMethod(name = "user.get", path="user/get")
	public User getUser(@Named("id") Long id) {
		PersistenceManager mgr = getPersistenceManager();
		User user = null;
		try {
			user = mgr.getObjectById(User.class, id);
		} finally {
			mgr.close();
		}
		return user;
	}

	@ApiMethod(name = "user.insert", path="user/insert")
	public User insertUser(User user) {
		PersistenceManager mgr = getPersistenceManager();
		user.setUserId(getUserIdLast() + 1);
		try {
			if (containsUser(user)) {
				throw new EntityExistsException("Object already exists");
			}
			mgr.makePersistent(user);
		} finally {
			mgr.close();
		}
		return user;
	}

	@ApiMethod(name = "user.update", path="user/update")
	public User updateUser(User user) {
		PersistenceManager mgr = getPersistenceManager();
		try {
			if (!containsUser(user)) {
				throw new EntityNotFoundException("Object does not exist");
			}
			mgr.makePersistent(user);
		} finally {
			mgr.close();
		}
		return user;
	}

	@ApiMethod(name = "user.remove", path="user/remove")
	public void removeUser(@Named("id") Long id) {
		PersistenceManager mgr = getPersistenceManager();
		try {
			User user = mgr.getObjectById(User.class, id);
			mgr.deletePersistent(user);
		} finally {
			mgr.close();
		}
	}
	
 	private long getUserIdLast() {
 		PersistenceManager mgr = getPersistenceManager();
 		long lastId = 0L;
 		User user = null;
 		List<User> execute = null;
 		Cursor cursor = null;
 		try {
 			Query query = mgr.newQuery(User.class);
 			query.setOrdering(User.USER_ID + " ascending" ); 
 			execute = (List<User>) query.execute();
 			cursor = JDOCursorHelper.getCursor(execute);

			for (User obj : execute)
 				lastId = obj.getUserId();
 		} finally {
 			mgr.close();
 		}
 		return lastId;
 	}
 
	private boolean containsUser(User user) {
		PersistenceManager mgr = getPersistenceManager();
		boolean contains = true;
		try {
			mgr.getObjectById(User.class, user.getUserId());
		} catch (javax.jdo.JDOObjectNotFoundException ex) {
			contains = false;
		} finally {
			mgr.close();
		}
		return contains;
	}

	private static PersistenceManager getPersistenceManager() {
		return PMF.get().getPersistenceManager();
	}

}
